package cn.wgx.common.security.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpRequest;
import cn.wgx.common.constant.UaaConstant;
import cn.wgx.common.entity.sys.Role;
import cn.wgx.common.security.client.config.entity.LoginAppUser;
import cn.wgx.common.security.client.config.tokenstore.RedisTemplateTokenStore;
import cn.wgx.common.security.feign.module.sysuser.SysUserFeign;
import cn.wgx.common.util.*;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;

import java.util.*;

public class SysUserUtil {

    private static SysUserFeign sysUserFeign = SpringUtils.getBean(SysUserFeign.class);
    private static RedisTemplate redisTemplate = SpringUtils.getBean("redisTemplate", RedisTemplate.class);
    private static TokenStore tokenStore = SpringUtils.getBean("tokenStore");

    public static LoginAppUser getLoginAppUser() {
        return getLoginAppUser(null);
    }

    /**
     * 更新当前用户信息/权限
     */
    public static void updateUserSession(String token) {
        //无token无法修改
        if(StringUtils.isBlank(token)){
            token = ServletUtils.getRequestParamByKey("access_token");
            if(token == null){
                return;
            }
        }
        //todo 更新当前用户动态信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication instanceof OAuth2Authentication) {
            OAuth2Authentication oldOAuth2Authentication = (OAuth2Authentication) authentication;
            Authentication userAuthentication = oldOAuth2Authentication.getUserAuthentication();
            if(userAuthentication instanceof UsernamePasswordAuthenticationToken){
                UsernamePasswordAuthenticationToken oldUsernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken)userAuthentication;
                Object principal = oldUsernamePasswordAuthenticationToken.getPrincipal();
                if(principal instanceof LoginAppUser){
                    LoginAppUser oldLoginAppUser = (LoginAppUser)principal;
                    LoginAppUser newLoginAppUser = sysUserFeign.findByUsername(oldLoginAppUser.getUsername());
                    //创建新的token,只替换loginappuser信息,其他的都用原来的数据
                    UsernamePasswordAuthenticationToken newUsernameToken = new UsernamePasswordAuthenticationToken(newLoginAppUser, oldUsernamePasswordAuthenticationToken.getCredentials());
                    newUsernameToken.setDetails(newLoginAppUser);
                    OAuth2Authentication newOAuth2Authentication = new OAuth2Authentication(oldOAuth2Authentication.getOAuth2Request(), newUsernameToken);
                    newOAuth2Authentication.setAuthenticated(oldOAuth2Authentication.isAuthenticated());
                    newOAuth2Authentication.setDetails(newLoginAppUser);
                    OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
                    tokenStore.storeAccessToken(oAuth2AccessToken, newOAuth2Authentication);

                }
            }
        }
    }


    /**
     * 获取当前登录用户信息
     *
     * @param access_token 可以为空,为空时会自动从请求参数中获取一次
     * @return 没找到返回空
     */
    public static LoginAppUser getLoginAppUser(String access_token) {
        if (access_token == null) {
            access_token = TokenUtil.getToken();
        }
        if (access_token != null) {
            LoginAppUser loginAppUser = (LoginAppUser) redisTemplate.opsForValue().get(RedisTemplateTokenStore.TOKEN + access_token);
            if (loginAppUser != null) {
                return loginAppUser;
            }
        }
        // 当OAuth2AuthenticationProcessingFilter设置当前登录时，直接返回
        // 强认证时处理
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication instanceof OAuth2Authentication) {
            OAuth2Authentication oAuth2Auth = (OAuth2Authentication) authentication;
            Authentication authentication2 = oAuth2Auth.getUserAuthentication();

            if (authentication2 instanceof UsernamePasswordAuthenticationToken) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) authentication2;

                if (usernamePasswordAuthenticationToken.getPrincipal() instanceof LoginAppUser) {
                    return (LoginAppUser) usernamePasswordAuthenticationToken.getPrincipal();
                } else if (usernamePasswordAuthenticationToken.getPrincipal() instanceof Map) {

                    LoginAppUser loginAppUser = BeanUtil.mapToBean((Map) usernamePasswordAuthenticationToken.getPrincipal(), LoginAppUser.class, true);
                    Set<Role> roles = new HashSet<>();
                    if (CollectionUtil.isNotEmpty(loginAppUser.getSysRoles())) {
                        for (Iterator<Role> it = loginAppUser.getSysRoles().iterator(); it.hasNext(); ) {
                            Role role = BeanUtil.mapToBean((Map) it.next(), Role.class, false);
                            roles.add(role);
                        }
                    }
                    loginAppUser.setSysRoles(roles);
                    return loginAppUser;
                }
            } else if (authentication instanceof PreAuthenticatedAuthenticationToken) {
                // 刷新token方式
                PreAuthenticatedAuthenticationToken authenticationToken = (PreAuthenticatedAuthenticationToken) authentication;
                return (LoginAppUser) authenticationToken.getPrincipal();
            }
        }

        return null;
    }

    public static LoginAppUser getLoginUserByUsername(String u) {
        LoginAppUser userByName = sysUserFeign.findByUsername(u);
        return userByName;
    }


    public static LoginAppUser getLoginUserByMobile(String m) {
        LoginAppUser userByName = sysUserFeign.findByMobile(m);
        return userByName;
    }


}
